package com.cdy.server.netty;

import com.cdy.common.property.CommonProperty;
import com.cdy.server.handler.HandlerManager;
import com.cdy.store.manager.FileSystem;
import com.cdy.store.repository.FileRepository;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

/**
 * netty的传输服务器
 * <p>
 * Created by 陈东一
 * 2019/10/19 0019 19:39
 */
@Slf4j
public class NettyServer {

    public static final AttributeKey<String> CLIENT_ID = AttributeKey.valueOf("clientId");
    private final EventLoopGroup boss = new NioEventLoopGroup(1);
    private final EventLoopGroup work = new NioEventLoopGroup();
    private final FileRepository fileRepository;
    private final FileSystem fileSystem;
    private ServerChannel channel;

    public NettyServer(FileRepository fileRepository, FileSystem fileSystem) {
        this.fileRepository = fileRepository;
        this.fileSystem = fileSystem;
    }

    public void init(String ip, Integer port) {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(boss, work)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline()
//                                .addLast(new FlowControlHandler())  //流量控制
//                                .addLast(new ChannelTrafficShapingHandler()) //流量整形
//                                .addLast(new ReadTimeoutHandler(60)) // 读心跳
                                .addLast(new ServerDecodeHandler())
                                .addLast(new ServerEncodeHandler())
                                .addLast(new ServerHandler(new HandlerManager(fileRepository,fileSystem)))
                                .addLast(new ServerErrorHandler())
                        ;

                    }
                })
                .option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(0, Math.toIntExact(CommonProperty.BigSectionLength) * 10))
                .option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true);

        ChannelFuture channelFuture = bootstrap.bind(ip, port);
        channelFuture.syncUninterruptibly();
        this.channel = (ServerChannel) channelFuture.channel();
    }

    public void close() {
        channel.close();
        boss.shutdownGracefully();
        work.shutdownGracefully();
    }

}
